package br.com.ordersys.framework.db;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import br.com.ordersys.framework.db.metadata.FieldMetadata;
import br.com.ordersys.framework.db.metadata.TableMetadata;
import br.com.ordersys.framework.db.utils.DBUtils;

public class DefaultSequenceKeygen implements IKeyGenerator {
	private String sql; 
	private TableMetadata tm;
	private FieldMetadata keyMemberToGenerate;
	private Collection<FieldMetadata> criteriaFields;
	
	@Override
	public void setMetadata(TableMetadata tm, FieldMetadata keyMemberToGenerate, Collection<FieldMetadata> keys) {
		this.tm = tm;
		this.keyMemberToGenerate = keyMemberToGenerate;
		
		StringBuilder buf = new StringBuilder();
		
		buf.append("SELECT MAX(").append(keyMemberToGenerate.getName()).append(") FROM ").append(tm.getInternalName());
		
		if(keys.size() > 1) {
			buf.append(" WHERE ");
			criteriaFields = new ArrayList<FieldMetadata>();
			StringBuilder criteriaBuf = new StringBuilder();
			
			for(Iterator<FieldMetadata> ite = keys.iterator(); ite.hasNext();) {
				FieldMetadata f = ite.next();
				if(f.getName().equals(keyMemberToGenerate.getName())) {
					continue;
				}
				
				if(criteriaBuf.length() > 0){
					criteriaBuf.append(" AND ");
				}

				criteriaBuf.append(f.getName()).append(" = ?");
				
				criteriaFields.add(f);
			}
			
			buf.append(criteriaBuf.toString());
		}
		
		sql = buf.toString();
	}
	
	@Override
	public Object generate(IValueObject vo, Connection c) {
		PreparedStatement pstm = null;
		try {
			pstm = DBUtils.getForwardReadOnlyStatement(sql, c);
			
			if(criteriaFields != null) {
				int i = 1;
				for(FieldMetadata f : criteriaFields ) {
					pstm.setObject(i++, vo.asObject(f.getName()));
				}
			}
			
			ResultSet rset = pstm.executeQuery();
			
			BigDecimal result = null;
			
			if(rset.next()) {
				result = rset.getBigDecimal(1);
			}
			
			if(result == null){
				result = BigDecimal.ZERO;
			}
			
			return result.add(BigDecimal.ONE);
		}catch(Exception e) {
			DBError.throwMe(e);
		}finally {
			DBUtils.closeResource(pstm);
		}
		return null;
	}

}
